package com.suning.sawp.service.impl.sys;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.suning.framework.sedis.JedisAction;
import com.suning.framework.sedis.JedisClient;
import com.suning.framework.vcsms.client.entity.Result;
import com.suning.sawp.constants.ErrorCodeConstants;
import com.suning.sawp.constants.SMSErrCodeConstants;
import com.suning.sawp.dto.common.QueryResult;
import com.suning.sawp.dto.common.ReturnMsg;
import com.suning.sawp.dto.mainpush.StoreManDto;
import com.suning.sawp.dto.sys.Categories;
import com.suning.sawp.dto.sys.LoginLogShowDto;
import com.suning.sawp.dto.sys.StoreManBindDeviceInfo;
import com.suning.sawp.dto.sys.StoreManDeviceDto;
import com.suning.sawp.dto.sys.UserInfo;
import com.suning.sawp.intf.bind.BindConstants;
import com.suning.sawp.intf.bind.BindDeviceService;
import com.suning.sawp.intf.dao.StoreManLoginLogDaoService;
import com.suning.sawp.intf.sms.SmsService;
import com.suning.sawp.intf.storeman.StoreManService;
import com.suning.sawp.intf.sys.SystemService;
import com.suning.sawp.po.StoreManLoginLog;
import com.suning.sawp.service.util.DJStringUtils;
import com.suning.sawp.service.util.DateUtils;
import com.suning.sawp.service.util.GsonUtils;
import com.suning.sawp.service.util.RedisCacheUtils;
import com.suning.vgs.follow.remote.intf.StoreManRemoteService;
import com.suning.vgs.follow.remote.store.ShopGuideDto;
import com.suning.vgs.follow.remote.store.StoreManBaseDto;
import com.suning.vgs.follow.remote.store.StoreManDeviceParam;
import com.suning.vgs.follow.remote.store.StoreManMoible;
import com.suning.vgs.follow.remote.store.StoreWorkerInfo;

import redis.clients.jedis.Jedis;

/**
 * 
 * 系统管理服务类<br> 
 * 〈功能详细描述〉
 *
 * @author 14062606
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
@Service
public class SystemServiceImpl implements SystemService{

    private static final Logger LOGGER = LoggerFactory.getLogger(SystemServiceImpl.class);
    
    /**
     * 公司号
     */
    private static final String COMPANY_PHONE = "1";
    
    private static final String STAFF_DEVICE_INFO = "com.suning.sawp:validDeviceId:staffId:";
    
	/**
	 * follow 保存用户发展用户信息接口
	 */
	@Resource
	StoreManRemoteService storeManRemoteService;

	@Resource
	SmsService smsService;
	
	@Resource
	JedisClient jedisClient;
	
	@Resource
	StoreManLoginLogDaoService storeManLoginLogDaoService;
	
	@Autowired
	private RedisCacheUtils redisClient;
	
	@Resource
	StoreManService storeManService;
	
	@Resource
	BindDeviceService bindDeviceService;
	
	@Override
	public ReturnMsg<UserInfo> queryUserInfo(String staffId) {
		ReturnMsg<UserInfo> userInfoRtn = new ReturnMsg<UserInfo>();
		
		StoreWorkerInfo storeWorkerInfo = storeManRemoteService.getWorkInfo(staffId);
		com.suning.vgs.follow.remote.store.ReturnMsg<StoreManBaseDto> storeBaseDto = 
				storeManRemoteService.getStoreManInfoWhenLogin(staffId);
		//对数据库的数据做更新操作
		storeManRemoteService.upsertStoreManBaseInfo(storeWorkerInfo, new Date(), staffId);
		// 清除redis中存储的店员附属信息
		storeManService.removeStoreManAttachInfoCache(staffId);
		// 清除redis中存储的首页缓存信息
		storeManService.removeIndexShowDataCache(staffId);
		UserInfo userInfo = dataTransfor(storeWorkerInfo, storeBaseDto, new Date());
		userInfoRtn.setData(userInfo);
		userInfoRtn.setRetFlag(ReturnMsg.SUCCESS);
		return userInfoRtn;
	}

	/**
	 * 将查询出的uuq职员信息转换成客户端展示信息
	 * @param storeWorkerInfo
	 * @param storeBaseDto
	 * @return
	 */
	private UserInfo dataTransfor(StoreWorkerInfo storeWorkerInfo, 
			com.suning.vgs.follow.remote.store.ReturnMsg<StoreManBaseDto> storeBaseDto, Date updateDate){
		UserInfo userInfo = new UserInfo();
		//验单资格
		String verifyOrderFlag = storeBaseDto.getData().getVerifyOrderFlag();
		//品类列表信息
		List<ShopGuideDto> shopGuideList = storeBaseDto.getData().getGuides();
		
		List<Categories> categoriesList = new ArrayList<Categories>();
		if (CollectionUtils.isNotEmpty(shopGuideList)){
			for (ShopGuideDto shopGuideDto : shopGuideList){
				Categories categories = new Categories();
				String categoryCode = shopGuideDto.getCategoryCode();
				String categoryName = shopGuideDto.getCategoryName();
				categories.setCategoryCode(categoryCode);
				categories.setCategoryName(categoryName);
				categoriesList.add(categories);
			}
		} else {
			Categories categories = new Categories();
			categories.setCategoryCode("");
			categories.setCategoryName("");
			categoriesList.add(categories);
		}
		userInfo.setCategories(categoriesList);
		userInfo.setVerifyOrderFlag(verifyOrderFlag);
		if (StringUtils.isNotBlank(storeWorkerInfo.getStoreCode()) && 
				!("null".equals(storeWorkerInfo.getStoreCode()))){
			userInfo.setStoreCode(storeWorkerInfo.getStoreCode());
			userInfo.setStoreName(storeWorkerInfo.getStoreName());
		} else {
			userInfo.setStoreCode(storeBaseDto.getData().getFdStoreCode());
			userInfo.setStoreName(storeBaseDto.getData().getStoreName());
		}
		userInfo.setMobile(storeWorkerInfo.getWorkerPhoneNum());
		userInfo.setName(storeWorkerInfo.getWorkerName());
		userInfo.setPositionId(storeWorkerInfo.getPositionId());
		userInfo.setPositionName(storeWorkerInfo.getPositionName());
		userInfo.setStationCode(storeWorkerInfo.getStationCode());
		userInfo.setStationName(storeWorkerInfo.getStationName());
		userInfo.setStaffId(storeBaseDto.getData().getStaffId());
		userInfo.setCityCode(storeBaseDto.getData().getCityCode());
		userInfo.setHeadPicNo(storeBaseDto.getData().getHeadPicNo());
		userInfo.setHeadPicType(storeBaseDto.getData().getHeadPicType());
		userInfo.setLastUpdateTime(DateUtils.getDateStrByFormat(updateDate, ""));
		
		return userInfo;
	}

    @Override
    public ReturnMsg<StoreManMoible> queryStoreManMobile(String staffId) {
        ReturnMsg<StoreManMoible> returnMsg = new ReturnMsg<StoreManMoible>();
        StoreManMoible moible = storeManRemoteService.queryStoreManMobileByStaffId(staffId);
        LOGGER.info("SystemService.queryStoreManMobile staffId:{}, mobileResult:{}"
                , staffId, moible.toString());
        String companyPhone = "";
        String personalPhone = "";
        if (StringUtils.isNotBlank(moible.getCompanyMobile())) {
            companyPhone = DJStringUtils.desensitiseMobile(moible.getCompanyMobile());
        }
        if (StringUtils.isNotBlank(moible.getPersonalMobile())) {
            personalPhone = DJStringUtils.desensitiseMobile(moible.getPersonalMobile());
        }
        moible.setCompanyMobile(companyPhone);
        moible.setPersonalMobile(personalPhone);
        returnMsg.setData(moible);
        return returnMsg;
    }

    @Override
    public ReturnMsg<String> sendDeviceSms(String staffId, String requestIp, String mobileType) {
        ReturnMsg<String> returnMsg = new ReturnMsg<String>();
        StoreManMoible storeManMoible = storeManRemoteService.queryStoreManMobileByStaffId(staffId);
        String mobile = storeManMoible.getPersonalMobile();
        if (COMPANY_PHONE.equals(mobileType)) {
            mobile = storeManMoible.getCompanyMobile();
        }
        
        Result result = smsService.generateSmsCode(mobile, staffId, requestIp, 
                SmsService.SmsConstants.SCENEID_DEVICE_VALID);
        if (SMSErrCodeConstants.CODE_1001.equals(result.getErrcode())) {
            // 短信发送成功
        } else {
            returnMsg.setErrorCode(result.getErrcode());
            returnMsg.setRetFlag(ReturnMsg.FAIL);
            returnMsg.setErrorMessage(SMSErrCodeConstants.getValue(result.getErrcode()));
        }
        return returnMsg;
    }

    @Override
    public ReturnMsg<String> validDeviceSms(String staffId, StoreManDto staffInfo,
    		String mobileType, String validCode, String deviceName, String deviceId, String ip) {
        ReturnMsg<String> returnMsg = new ReturnMsg<String>();
        StoreManMoible storeManMoible = storeManRemoteService.queryStoreManMobileByStaffId(staffId);
        String mobile = storeManMoible.getPersonalMobile();
        if (COMPANY_PHONE.equals(mobileType)) {
            mobile = storeManMoible.getCompanyMobile();
        }
        
        Result result = smsService.validateSmsCode(mobile, validCode, null,
                SmsService.SmsConstants.SCENEID_DEVICE_VALID);
        if (SMSErrCodeConstants.CODE_1002.equals(result.getErrcode())) {
            // 校验成功，绑定设备ID
            // 根据设备ID查询是否存在绑定信息
            StoreManBaseDto baseDto = storeManRemoteService.queryStoreManBaseInfoByStaffId(staffId);
            if (null != baseDto) {
                // 清除原有的设备ID
                LOGGER.info("System.validDeviceSms deviceId has bind romve deviceId={}", deviceId);
                unBindStaffIdDevice(baseDto.getStaffId(), baseDto.getDeviceId(), baseDto.getDeviceName());
                // 删除本地库的绑定信息
                bindDeviceService.deleteBindInfo(staffId);
            }
            // 绑定新的设备ID
            bindStaffIdDevice(staffId, deviceId, deviceName);
            // 在本地库新增绑定信息
            boolean bindFlag = bindDeviceService.addBindInfo(staffId, staffInfo, deviceId, deviceName, 
            		staffInfo.getStaffId(), staffInfo.getStaffName(), BindConstants.OP_SLEF_BIND, ip);
            if (!bindFlag) {
                returnMsg.setRetFlag(ReturnMsg.FAIL);
                returnMsg.setErrorMessage("添加用户绑定记录失败");
            }
        } else {
            returnMsg.setErrorCode(result.getErrcode());
            returnMsg.setRetFlag(ReturnMsg.FAIL);
            returnMsg.setErrorMessage(SMSErrCodeConstants.getValue(result.getErrcode()));
        }
        return returnMsg;
    }

    /**
     * 
     * 功能描述: 绑定工号-设备ID<br>
     * 〈功能详细描述〉
     *
     * @param staffId
     * @param deviceId
     * @param deviceName
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private void bindStaffIdDevice(String staffId, String deviceId, String deviceName) {
        // 更新此对设备绑定关系
        storeManRemoteService.updateStoreManDeviceId(staffId, deviceId, deviceName, new Date());
        // 清除redis中现有的工号-设备ID绑定关系
        final String key = STAFF_DEVICE_INFO + staffId;
        jedisClient.execute(new JedisAction<Long>() {
            @Override
            public Long doAction(Jedis jedis) {
                return jedis.del(key);
            }
        });
        Object[] args = {staffId, deviceId, deviceName};
        LOGGER.info("validDeviceSms bind device staffId:{}, deviceId:{}, deviceName:{}", args);
        
    }

    /**
     * 
     * 功能描述: 解除绑定设备ID<br>
     * 〈功能详细描述〉
     *
     * @param staffId
     * @param deviceId
     * @param deviceName
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private void unBindStaffIdDevice(String staffId, String deviceId, String deviceName) {
     // 清除此设备绑定关系
        storeManRemoteService.updateStoreManDeviceId(staffId, null, null, null);
        // 清除redis中此对绑定关系
        final String deviceIdkey = STAFF_DEVICE_INFO + staffId;
        jedisClient.execute(new JedisAction<Long>() {
            @Override
            public Long doAction(Jedis jedis) {
                return jedis.del(deviceIdkey);
            }
        });
        Object[] args = {staffId, deviceId, deviceName};
        LOGGER.info("validDeviceSms remove device bind staffId:{}, deviceId:{}, deviceName:{}", args);
        
    }
    
    @Override
    public ReturnMsg<QueryResult<LoginLogShowDto>> queryLoginLogs(String staffId, int pageSize, int pageNo) {
        ReturnMsg<QueryResult<LoginLogShowDto>> ret = new ReturnMsg<QueryResult<LoginLogShowDto>>();
        // 查询此店员的登录日志总记录
        int totalSize = storeManLoginLogDaoService.countLoginLogs(staffId);
        int startIndex = pageNo < 1 ? 0 : (pageNo - 1) * pageSize;
        List<StoreManLoginLog> records = storeManLoginLogDaoService.queryLoginLogs(staffId, startIndex, pageSize);
        List<LoginLogShowDto> list = new ArrayList<LoginLogShowDto>();
        for (StoreManLoginLog log : records) {
            LoginLogShowDto dto = new LoginLogShowDto();
            dto.setStaffId(log.getStaffId());
            dto.setDeviceId(log.getDeviceId());
            dto.setDeviceName(log.getDeviceName());
            dto.setLoginIp(log.getLoginIp());
            dto.setLoginTimeStr(DateUtils.getDateStrByFormat(
                    log.getLoginTime(), DateUtils.DEFAULY_FULL_TIME_PATTERN));
            list.add(dto);
        }
        QueryResult<LoginLogShowDto> queryResult = new QueryResult<LoginLogShowDto>(totalSize, list);
        ret.setData(queryResult);
        
        return ret;
    }

    @Override
    public ReturnMsg<QueryResult<StoreManDeviceDto>> queryStoreManDeviceInfo(StoreManDeviceParam param) {
        ReturnMsg<QueryResult<StoreManDeviceDto>> returnMsg = new ReturnMsg<QueryResult<StoreManDeviceDto>>();
        QueryResult<StoreManDeviceDto> queryResult = new QueryResult<StoreManDeviceDto>();
        // 如果有合法工号，大区、门店置为空
        if (StringUtils.isNotBlank(param.getStaffId())) {
            param.setRegionCode(null);
            param.setStoreCode(null);
        }
        // 查询店员绑定设备总记录数
        int totalSize = storeManRemoteService.countStoreManBindDeviceInfo(param);
        List<StoreManBaseDto> list = storeManRemoteService.queryStoreManBindDeviceInfos(param);
        List<StoreManDeviceDto> deviceDtos = new ArrayList<StoreManDeviceDto>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (StoreManBaseDto baseDto : list) {
                StoreManDeviceDto deviceDto = new StoreManDeviceDto();
                deviceDto.setDeviceId(baseDto.getDeviceId());
                deviceDto.setDeviceName(baseDto.getDeviceName());
                deviceDto.setRegionName(baseDto.getRegionName());
                deviceDto.setStoreName(baseDto.getStoreName());
                String bindStatus = "0";// 未绑定
                if (StringUtils.isNotBlank(baseDto.getDeviceId())) {
                    bindStatus = "1";// 已绑定
                }
                deviceDto.setBindStatus(bindStatus);
                if (null != baseDto.getDeviceBindTime()) {
                    deviceDto.setBindTime(DateUtils.getDateStrByFormat(
                            baseDto.getDeviceBindTime(), DateUtils.ACCURATE_MINUTES_PATTERN));
                }
                List<StoreManLoginLog> logs = storeManLoginLogDaoService
                        .queryLoginLogs(baseDto.getStaffId(), 0, 1);
                if (CollectionUtils.isNotEmpty(logs)) {
                    deviceDto.setLastestLoginTime(DateUtils.getDateStrByFormat(
                            logs.get(0).getLoginTime(), DateUtils.ACCURATE_MINUTES_PATTERN));
                }
                deviceDto.setStaffId(baseDto.getStaffId());
                
                deviceDtos.add(deviceDto);
            }
        }
        
        queryResult.setRecords(deviceDtos);
        queryResult.setTotalSize(totalSize);
        returnMsg.setData(queryResult);
        return returnMsg;
    }

    @Override
    public ReturnMsg<String> unBindDevice(String staffId, String opStaffId) {
        ReturnMsg<String> msg = new ReturnMsg<String>();
        LOGGER.info("SystemService.unBindDevice staffId:{}, opStaffId:{}", staffId, opStaffId);
        try {
            // 解绑DB此工号对应绑定关系
            storeManRemoteService.updateStoreManDeviceId(staffId, null, null, null);
            // 清除redis中此对绑定关系
            final String deviceIdkey = STAFF_DEVICE_INFO + staffId;
            jedisClient.execute(new JedisAction<Long>() {
                @Override
                public Long doAction(Jedis jedis) {
                    return jedis.del(deviceIdkey);
                }
            });
            
            // 删除本地库绑定信息
            bindDeviceService.deleteBindInfo(staffId);
        } catch (Exception e) {
            msg.setError(ErrorCodeConstants.ERR_0002);
            Object[] args = {staffId, opStaffId};
            LOGGER.error("SystemService.unBindDevice staffId:{}, opStaffId:{} error", args, e);
        }
         
        return msg;
    }

    @Override
    public ReturnMsg<String> bindDevice(String staffId, String opStaffId, String opStaffName) {
        LOGGER.info("systemSerive.bindDevice staffId:{}, opStaffId:{}", staffId, opStaffId);
        ReturnMsg<String> msg = new ReturnMsg<String>();
        // 取登录日志最近的记录
        List<StoreManLoginLog> lastestLog = storeManLoginLogDaoService.queryLoginLogs(staffId, 0, 1);
        if (CollectionUtils.isNotEmpty(lastestLog)
                && StringUtils.isNotBlank(lastestLog.get(0).getDeviceId())) {
            String deviceId = lastestLog.get(0).getDeviceId();
            String deviceName = lastestLog.get(0).getDeviceName();
            // 更新设备ID
            StoreManDto staffInfo = storeManService.queryStoreManAttachInfo(staffId);
            bindStaffIdDevice(staffId, deviceId, deviceName);
            // 在本地库新增绑定信息
            bindDeviceService.addBindInfo(staffId, staffInfo, deviceId, deviceName, 
            		opStaffId, opStaffName, BindConstants.OP_ADMIN_BIND, null);
        } else {
            // 如果没有，提示查无对应设备ID
            msg.setError(ErrorCodeConstants.ERR_1016);
        }
        return msg;
    }

    @Override
    public StoreManBindDeviceInfo getCacheDeviceInfo(final String staffId) {
        StoreManBindDeviceInfo bindDeviceInfo = null;
        String deviceInfo = redisClient.get(STAFF_DEVICE_INFO + staffId);
        
        if (StringUtils.isBlank(deviceInfo)) {
            // 如果缓存中没有查找到绑定设备信息，查询DB获取设备信息
            StoreManBaseDto baseDto = 
                    storeManRemoteService.queryStoreManBaseInfoByStaffId(staffId);
            if (null != baseDto && StringUtils.isNotBlank(baseDto.getDeviceId())) {
                bindDeviceInfo = new StoreManBindDeviceInfo(baseDto.getDeviceId(), 
                        baseDto.getDeviceName(), DateUtils.getDateStrByFormat(
                                baseDto.getDeviceBindTime(), DateUtils.ACCURATE_MINUTES_PATTERN));
                // 将DB中查询得到的绑定设备信息存入缓存，有效期设置两小时
                String deviceJson = GsonUtils.toJson(bindDeviceInfo, false);
                redisClient.setex(STAFF_DEVICE_INFO + staffId, 7200, deviceJson);
            }
        } else {
            bindDeviceInfo = GsonUtils.fromJson(deviceInfo, StoreManBindDeviceInfo.class);
        }
        
        return bindDeviceInfo;
    }
}
